package view.overlay;

import interaction.InteractionCommand;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Rectangle2D;
import java.util.LinkedHashMap;
import java.util.Map;

import scheduler.DuplicateEventException;
import scheduler.Notifiable;
import scheduler.Scheduler;

public class InteractionOverlay extends PassiveOverlay {
	
	private int mDestShutterPadding = 100;
	
	private int mCurShutterHeight;
	
	private Rectangle mShutterTop;
	private Rectangle mShutterBottom;
	
	private int mSpeed;
	
	
	private Notifiable mFadeIn;
	private Notifiable mFadeOut;
	
	private boolean isFading;
	
	private Map<InteractionCommand, MouseListener> mOptionListeners;
	
	private Map<InteractionCommand, Button> mOptionButtons;
	
	private Rectangle mMessageBounds;
	
	private String mMessage;
	
	private boolean mIsVisible;
	
	
	public InteractionOverlay() {
		mSpeed = 10;
		
		calculateBounds();
		isFading = false;
		mIsVisible = false;
		mOptionButtons = new LinkedHashMap<InteractionCommand, Button>();
		
		
		mFadeIn = new Notifiable() {
				
			@Override
			public void execute() {
				// invalidate
				InteractionOverlay.this.invalidate();
				mCurShutterHeight += mSpeed;
				calculateBounds();
				
				if (mCurShutterHeight >= mDestShutterPadding) {
					// stop
					Scheduler.getPersistantClock().cancel(this);
					isFading = false;
					mIsVisible = true;
				}
				
			}
			
		};
		
		
		mFadeOut = new Notifiable() {
			
			@Override
			public void execute() {
				// invalidate
				InteractionOverlay.this.invalidate();
				mCurShutterHeight -= mSpeed;
				calculateBounds();
				
				if (mCurShutterHeight <= 0) {
					// stop
					Scheduler.getPersistantClock().cancel(this);
					isFading = false;
					mIsVisible = false;
				}
				
			}
			
		};
		
		
	}
	

	@Override
	protected void paint(Graphics g) {
		// draw the overlay borders
		g.setColor(Color.BLACK);
		
		g.fillRect(mShutterTop.x, mShutterTop.y, mShutterTop.width, mShutterTop.height);
		g.fillRect(mShutterBottom.x, mShutterBottom.y, mShutterBottom.width, mShutterBottom.height);
		
		if (!isFading) {
			// Only display the buttons when NOT fading
			
			if (mIsVisible) {
				for (InteractionCommand ic : mOptionButtons.keySet()) {
					Button b = mOptionButtons.get(ic);
					
					if (b == null) continue;
					b.draw(g);
					
				}
				
				if (mMessage != null) {
					// Draw the text if there is one
					g.setColor(Color.WHITE);
					String[] lines = mMessage.split("\n");
					int yOffset = 10;
					for (String line : lines) {
						Rectangle2D lineBounds = g.getFontMetrics().getStringBounds(mMessage, g);
						g.drawString(line, (int)(mMessageBounds.x + mMessageBounds.width / 2 - lineBounds.getWidth() / 2), yOffset);
						
						yOffset += lineBounds.getHeight();
					}
				}
			}
			
		}
		
	}

	@Override
	public Dimension getPreferredSize() {
		return (new Dimension(0, 0));
	}

	
	public void startInteraction() {
		isFading = true;
		mCurShutterHeight = 0;
		try {
			Scheduler.getPersistantClock().schedule(mFadeIn, 1);
		}
		catch (DuplicateEventException dee) {
			
		}
	}
	
	
	private void calculateBounds() {
		mDestShutterPadding = this.getHeight() / 6;
		mShutterTop = new Rectangle(0,
									0,
									this.getWidth(),
									mCurShutterHeight);
		
		mShutterBottom = new Rectangle(0,
										this.getHeight() - mCurShutterHeight,
										mShutterTop.width,
										mCurShutterHeight);
		
		
		int messageHeight = mDestShutterPadding;
		int messageWidth = 800;
		mMessageBounds = new Rectangle(mShutterTop.x + mShutterTop.width / 2 - messageWidth / 2,
										0,
										messageWidth,
										messageHeight);
		
		
		// Buttons
		int buttonWidth = 150;
		int buttonHeight = 40;
		
		int hPadding = 10;
		int yPadding = 10;
		
		if (mOptionButtons == null) return;
		
		int totalWidth = mOptionButtons.size() * (buttonWidth + hPadding);

		
		int xOffset = this.getWidth() / 2 - totalWidth / 2;
		int yOffset = mShutterBottom.y + mDestShutterPadding / 2 - buttonHeight / 2;
		
		
		
		for (InteractionCommand ic : mOptionButtons.keySet()) {
			Button b = mOptionButtons.get(ic);
			
			if (b == null) {
				b = new Button(ic.getID());
			}
			
			b.setBounds(xOffset,
						yOffset,
						buttonWidth,
						buttonHeight);
			
			xOffset += buttonWidth + hPadding;
		}
		
	}
	
	
	public void setMessage(String msg) {
		this.mMessage = msg;
		this.invalidate();
	}
	
	
	public void exitInteraction() {
		isFading = true;
		
		mCurShutterHeight = mDestShutterPadding;
		try {
			
			Scheduler.getPersistantClock().schedule(mFadeOut, 1);
		}
		catch (DuplicateEventException dee) {
			
		}
	}
	
	public void setInteractionOptions(Map<InteractionCommand, MouseListener> options) {
		mOptionListeners = options;
		
		mOptionButtons.clear();
		
		for (InteractionCommand ic : options.keySet()) {
			Button b = new Button(ic.getID());
			b.setListener(options.get(ic));
			mOptionButtons.put(ic, b);
		}
		
		calculateBounds();
	}
	
	@Override
	public void onMouseClicked(MouseEvent e) {
		
		
		for (InteractionCommand ic : mOptionButtons.keySet()) {
			Button b = mOptionButtons.get(ic);
			
			if (b != null) {
				if (b.contains(e.getPoint())) {
					b.activate(e);
				}
			}
		}
	}
	
	@Override
	public void resize(int width, int height) {
		super.resize(width, height);
		
		calculateBounds();
	}
}
